home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Tools 2
/
Amiga Tools 2.iso
/
grafik
/
bildanzeiger
/
egsflick
/
eflick.c
next >
Wrap
C/C++ Source or Header
|
1995-03-09
|
20KB
|
787 lines
/*
EGSFlick - Play .FLI/.FLC animations under EGS
Frank Neumann, November 1993
This program plays .FLI (fixed to 320x200) or .FLC (any
resolution) anim files in an EGS window on a graphic board
that is capable of producing an 8 bit, CLUT-based chunky pixel
display. This is true for most currently available Amiga graphic
boards, such as the Rainbow III, Piccolo, Spectrum and maybe
others that are still to come.
History:
V1.0 24.03.1993 First version, already stable, but not to
be released for a long time.
V1.1 14.11.1993 Thought it would be a good idea to release this
goodie - as EGS seems to become more and more
used around the world. First release.
V1.1a 19.11.1993 Removed the Map->Type test of the EScreen - seems
I have not yet understood some of EGS' concepts..
V1.2 13.09.1994 After a long break, a small addition: Now listens
to the environment variable 'EGSFLICK' which
determines another screen mode than the default.
This code is mostly based on xflick for X11 systems. What follows is
the original comment:
xflick - Ron Schnell, March, 1991
This code is provided as is, with no warrantees, expressed
or implied. I believe this code to be free of encumbrance,
and offer it to the public domain. I ask, however, that
this paragraph and my name be retained in any modified
versions of the file you may make, and that you notify me
of any improvements you make to the code.
Ron Schnell (ronnie@sos.com)
The following changes are from Michael Pall
(pall@rz.uni-karlsruhe.de) Mar 25-28 1991:
Lots of bugfixes and changes to the structure of the files.
The file is interpreted before we display it.
Moved the interpretation part to read.c.
We use Pixmaps and/or XImages.
Added interactive input to change the speed/single step.
The following extensions are from Klaus Ehrenfried
(klaus@spock.es.go.dlr.de) Oct 23-24 1992:
Add handling of FLI_DELTA and FLI_256_COLOR chunks.
Recognize magic number FLC_MAGIC = 0xaf12 for newer
flic files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/time.h>
#include "eflick.h"
#include <exec/types.h>
#include <clib/exec_protos.h>
#include <egs/egsintui.h>
#include <egs/clib/egsintui_protos.h>
#include <egs/egsgfx.h>
#include <egs/clib/egsgfx_protos.h>
#include <egs/egs.h>
#include <egs/clib/egs_protos.h>
/* Amiga version identification */
static char *version = "$VER: EGSFlick 1.2 (13.09.94)";
int verbose = 0;
static int jiffies;
/* pointers to required libraries */
struct Library *EGSIntuiBase = NULL;
struct Library *EGSBase = NULL;
struct Library *EGSGfxBase = NULL;
struct Library *EGSBlitBase = NULL;
struct EI_NewScreen newscreen = {
NULL, /* screenmode name is put here later... */
8, 0, "EGSFlick Screen", /* depth, pad, title */
NULL, /* CLUPtr */
{ 3, 1, 0, 2, 1, 3, 1 }, /* WinColors */
0, /* backPen */
NULL, /* backPattern */
NULL, /* Maus */
NULL /* TextAttr */
};
static struct EI_NewWindow newWindow =
{
50, 30, 10, 10, /* LeftEdge, TopEdge, Width, Height */
0, 0, 0, 0, /* MinWidth,MinHeight, MaxWidth, MaxHeight */
NULL, /* Screen - might be set to some screen later */
EI_WINDOWCLOSE | EI_WINDOWBACK | EI_WINDOWDRAG, /* SysGadgets */
NULL, /* FirstGadgets */
"EGSFlick V1.2 by Franky", /* Title */
EI_SMART_REFRESH | EI_GIMMEZEROZERO | EI_WINDOWACTIVE, /* Flags */
EI_iCLOSEWINDOW | EI_iVANILLAKEY | EI_iACTIVEWINDOW | EI_iINACTIVEWINDOW, /*EI_IDCMPFlags */
NULL, /*Port */
{0,0,0,0,0,0,0}, /* Colors */
NULL, /* Menu */
NULL /* Render */
};
EI_ScreenPtr screen = NULL;
EI_WindowPtr window = NULL;
E_EBitMapPtr map = NULL;
EG_RastPortPtr rp;
E_CLU oldscreencolors[MAXCOL], screencolors[MAXCOL];
static flag_noint = 0; /* Don't interpret file first */
static int fdelay; /* Frame delay */
static int wwidth, wheight; /* Width and height of the window */
char fliname[256];
/* a modified XColor structure definition */
typedef struct {
unsigned long pixel;
unsigned char red, green, blue;
} XColor;
/* The structure to hold the elements of the interpreted display list */
struct disp_list
{
int disp_type;
int disp_frame;
E_EBitMapPtr disp_pix;
XColor *disp_cols;
int disp_numcol;
int disp_width, disp_height;
int disp_destx, disp_desty;
struct disp_list *disp_next;
};
static struct disp_list disp_root; /* The start of the display list */
static struct disp_list *disp_cur; /* The current position */
extern void interpret_fli();
/* prototypes */
void Crash( char * );
/* Convert the frame delay to microseconds/seconds */
static void
convert_fdelay()
{
jiffies = (fdelay * 70) / 50;
}
/* Print a usage message and exit */
static void
usage()
{
(void) fprintf(stderr,
"Usage: EGSFlick [-v] [-r<count>] [-d<delay>] [-n] fli_file\n");
(void) fprintf(stderr, " -v Verbose Debugging info\n\
-r<count> Repeat count times (0 = loop forever)\n\
-d<delay> Delay between frames in 1/70s\n\
-n Don't interpret file before display \
(slower but uses less memory)\n");
exit(0);
}
/* Check for pending EI_iVANILLAKEY messages and process them */
static void
check_key()
{
struct EI_EIntuiMsg *msg;
static int stepflag = 0; /* Default: singlestep is off */
int onestep = stepflag; /* 1 if we should be loop waiting for a step */
while (NULL != (msg = (struct EI_EIntuiMsg *)GetMsg(window->UserPort)) || onestep)
{
if (msg != NULL)
{
switch (msg->Class)
{
case EI_iVANILLAKEY:
switch (msg->Code)
{
/* Minus: Slow down */
case '-':
fdelay++;
convert_fdelay();
break;
/* Plus: Speed up */
case '+':
if (fdelay)
fdelay--;
convert_fdelay();
break;
/* Space: Single step */
case ' ':
stepflag = 1;
onestep = 0;
break;
/* c: Continue animation */
case 'c':
stepflag = 0;
onestep = 0;
break;
/* 'q': Quit */
case 'q':
ReplyMsg(msg);
Crash(NULL);
break;
}
break;
case EI_iCLOSEWINDOW:
ReplyMsg(msg);
Crash(NULL);
break;
case EI_iACTIVEWINDOW:
E_SetRGB8CM(window->WScreen->EScreen, screencolors, 0, MAXCOL);
break;
case EI_iINACTIVEWINDOW:
E_SetRGB8CM(window->WScreen->EScreen, oldscreencolors, 0, MAXCOL);
break;
default:
printf("You don't really ever want to see this.\n");
break;
}
ReplyMsg((struct Message *)msg);
}
}
}
/* Function to display the interpretation immediately */
static void
func_disp(ftype, frame, buf, srcx, srcy, destx, desty, swidth, sheight)
int ftype;
int frame;
unsigned char *buf;
int srcx, srcy;
int destx, desty;
int swidth, sheight;
{
static int colchange=0; /* Colormap has changed */
switch (ftype)
{
case FLI_COPY:
case FLI_LC:
case FLI_DELTA:
case FLI_BRUN:
EG_CopyBitMapRastPort(map, rp, srcx, srcy, swidth, sheight, destx, desty);
break;
case FLI_BLACK:
EG_SetAPen(rp, 0x00000000);
EG_RectFill(rp, destx, desty, swidth, sheight);
break;
case FLI_COLOR:
while(srcy--)
{
screencolors[srcx].Red = ((*(buf++) & 0x3f) << 2);
screencolors[srcx].Green = ((*(buf++) & 0x3f) << 2);
screencolors[srcx].Blue = ((*(buf++) & 0x3f) << 2);
srcx++;
}
colchange = 1;
break;
case FLI_256_COLOR:
while(srcy--)
{
screencolors[srcx].Red = ((*(buf++) & 0xff));
screencolors[srcx].Green = ((*(buf++) & 0xff));
screencolors[srcx].Blue = ((*(buf++) & 0xff));
srcx++;
}
colchange = 1;
break;
case FLI_SYNC:
if (colchange)
{
E_SetRGB8CM(window->WScreen->EScreen, screencolors, 0, MAXCOL);
colchange = 0;
}
check_key();
/* Do we have a delay between the frames? */
if (jiffies)
Delay(jiffies);
break;
}
}
/* Store the interpretation */
static void
func_interp(ftype, frame, buf, srcx, srcy, destx, desty, swidth, sheight)
int ftype; /* The type of this chunk */
int frame; /* The number of this frame */
unsigned char *buf; /* A pointer to the pixel/colormap data */
int srcx, srcy; /* The upper left corner in the data array */
int destx, desty; /* The upper left corner in the window */
int swidth, sheight; /* The dimensions of the rectangle */
{
XColor *coltmp; /* Temporary storage for pointer to XColor struct */
/* set title of EGS window to current frame number */
char framenum[20];
sprintf(framenum, "load: frame %d", disp_cur->disp_frame);
EI_SetWindowTitles(window, framenum, (char *)-1);
/* Allocate another element in the display list */
disp_cur->disp_next = (struct disp_list *)malloc(sizeof(struct disp_list));
disp_cur = disp_cur->disp_next;
/* Clear the pointer to the next element so we find the end of the list */
disp_cur->disp_next = (struct disp_list *)0;
/* Copy info pertaining to all or most of the chunks */
disp_cur->disp_type = ftype;
disp_cur->disp_frame = frame;
disp_cur->disp_width = swidth;
disp_cur->disp_height = sheight;
disp_cur->disp_destx = destx;
disp_cur->disp_desty = desty;
disp_cur->disp_pix = (E_EBitMapPtr)NULL;
switch (ftype)
{
case FLI_COPY:
case FLI_LC:
case FLI_DELTA:
case FLI_BRUN:
disp_cur->disp_pix = E_AllocBitMap(wwidth, wheight, 8, E_PIXELMAP, 0, 0);
if (disp_cur->disp_pix == NULL)
Crash("could not allocate memory for picture");
disp_cur->disp_pix->Lock++;
EB_CopyBitMap(map, disp_cur->disp_pix, srcx, srcy, swidth, sheight, 0, 0, 0);
break;
case FLI_COLOR:
/* Create an array of XColor to hold the colors. Specific to FLI_COLOR:
srcx is the starting color index and srcy is the number of colors */
coltmp = (XColor *)malloc(srcy * sizeof(XColor));
disp_cur->disp_cols = coltmp;
disp_cur->disp_numcol = srcy;
/* Copy the changed colors to the XColor array */
while(srcy--)
{
coltmp->red = ((*(buf++) & 0x3f) << 2);
coltmp->green = ((*(buf++) & 0x3f) << 2);
coltmp->blue = ((*(buf++) & 0x3f) << 2);
coltmp->pixel = srcx++;
coltmp++;
}
break;
case FLI_256_COLOR:
/* Create an array of XColor to hold the colors. Specific to FLI_256_COLOR:
srcx is the starting color index and srcy is the number of colors */
coltmp = (XColor *)malloc(srcy * sizeof(XColor));
disp_cur->disp_cols = coltmp;
disp_cur->disp_numcol = srcy;
/* Copy the changed colors to the XColor array */
while(srcy--)
{
coltmp->red = ((*(buf++) & 0xff));
coltmp->green = ((*(buf++) & 0xff));
coltmp->blue = ((*(buf++) & 0xff));
coltmp->pixel = srcx++;
coltmp++;
}
break;
/* FLI_BLACK and FLI_SYNC only need to be stored */
case FLI_BLACK:
case FLI_SYNC:
break;
}
}
/* Display the stored interpretation */
static void
display_interp(dc)
struct disp_list *dc; /* The structure holding the info on the chunk */
{
static int colchange=0; /* Colormap has changed */
int idx, pixel, numcols;
int swidth, sheight; /* Dimension of the changing rectangle */
int destx, desty; /* Upper left corner of the rectangle */
/* Copy some fields from the structure */
swidth = dc->disp_width;
sheight = dc->disp_height;
destx = dc->disp_destx;
desty = dc->disp_desty;
switch (dc->disp_type)
{
case FLI_COPY:
case FLI_LC:
case FLI_DELTA:
case FLI_BRUN:
EG_CopyBitMapRastPort(dc->disp_pix, rp, 0, 0, swidth, sheight, destx, desty);
break;
case FLI_BLACK:
/* Clear the whole rectangle */
EG_SetAPen(rp, 0x00000000);
EG_RectFill(rp, destx, desty, swidth, sheight);
break;
case FLI_COLOR:
case FLI_256_COLOR:
/* Store the changed colors in the colormap and note that */
idx = 0;
numcols = dc->disp_numcol;
while(numcols--)
{
pixel = dc->disp_cols[idx].pixel;
screencolors[pixel].Red = dc->disp_cols[idx].red;
screencolors[pixel].Green = dc->disp_cols[idx].green;
screencolors[pixel].Blue = dc->disp_cols[idx].blue;
idx++;
}
colchange = 1;
break;
case FLI_SYNC:
/* If the colors have changed we set the colormap for the window */
if (colchange)
{
E_SetRGB8CM(window->WScreen->EScreen, screencolors, 0, MAXCOL);
colchange = 0;
}
check_key();
if (jiffies)
Delay(jiffies);
break;
}
}
/* Draw a given string to the center of the window */
static void
text_center(str)
char *str;
{
int w;
EG_SetAPen(rp, 0x00000000);
EG_RectFill(rp, 0, 0, wwidth, wheight);
/* Determine the width of the string */
w = EG_TextLength(rp, str, strlen(str));
if (w > wwidth)
w = wwidth;
/* And draw the string */
EG_SetAPen(rp, 0xffffff00);
EG_Move(rp, (wwidth-w)/2, wheight/2);
EG_Text(rp, str, strlen(str));
}
main(argc, argv)
int argc;
char *argv[];
{
int fd; /* For the main file descriptor */
struct fli_header header; /* To hold the main header */
unsigned char *data; /* Always has the current image data */
int repeatcount; /* How many times to loop */
unsigned char notfirst; /* Is this not the first time through? */
char *fname; /* Pointer to filename */
int depth; /* depth of (EGS default) screen */
unsigned char *mode; /* for env.-variable */
fdelay = -1;
repeatcount = 10;
/* required very early for (possible) error handling */
disp_root.disp_next = (struct disp_list *)0;
while (--argc && argv[1][0] == '-')
{
argv++;
switch (argv[0][1])
{
case 'r':
repeatcount = atol(&(argv[0][2]));
break;
case 'd':
fdelay = atol(&(argv[0][2]));
break;
case 'n':
flag_noint = 1;
break;
case 'v':
verbose = 1;
break;
default:
usage();
}
}
if (argc != 1)
usage();
fname = argv[1];
strcpy(fliname, argv[1]);
fd = open(fname, 0);
if (fd < 0)
{
(void) fprintf(stderr, "Error opening %s.\n", fname);
perror("EGSFlick");
exit(1);
}
/* Read the main FLI header */
read_flihead(fd, &header);
if (((header.fhd_magic & 0x0000ffff) != FLI_MAGIC) &&
((header.fhd_magic & 0x0000ffff) != FLC_MAGIC))
{
(void) fprintf(stderr, "%s, not a .fli file.\n", fname);
exit(0);
}
/* Get the width and height */
wwidth = header.fhd_width;
wheight = header.fhd_height;
/* The speed is stored in 1/70 seconds, convert to usecs */
if (fdelay < 0)
fdelay = header.fhd_speed;
convert_fdelay();
/* open the required EGS libraries */
EGSBase = OpenLibrary("egs.library", 0);
if (NULL == EGSBase)
Crash ("couldn't open 'egs.library' -- stop.");
EGSBlitBase = OpenLibrary("egsblit.library", 0);
if (NULL == EGSBlitBase)
Crash ("couldn't open 'egsblit.library' -- stop.");
EGSIntuiBase = OpenLibrary("egsintui.library", 0);
if (NULL == EGSIntuiBase)
Crash ("couldn't open 'egsintui.library' -- stop.");
EGSGfxBase = OpenLibrary("egsgfx.library", 0);
if (NULL == EGSGfxBase)
Crash ("couldn't open 'egsgfx.library' -- stop.");
/*
try to read environment variable 'EGSFLICK' - if set, use its
value as the screen mode name and force the window to open
on that screen instead of the EGS default screen
*/
mode = getenv("EGSFLICK");
if (mode != NULL)
{
/* EGSFLICK = "default" ? */
if (stricmp(mode, "default") != 0)
{
newscreen.Mode = mode;
screen = EI_OpenScreen(&newscreen);
if (screen == NULL)
Crash("Could not open EI_Screen");
newWindow.Screen = screen;
}
}
/*
open EGS window on the default screen, hoping that it's currently set
to 8 bit
*/
/* Create a wwidth x wheight window to show the flick */
newWindow.Width = wwidth;
newWindow.Height = wheight;
window = EI_OpenWindow(&newWindow);
if (window == NULL)
Crash("Couldn't open EGS window -- stop.");
/* save current color table */
E_GetRGB8CM(window->WScreen->EScreen, oldscreencolors, 0, MAXCOL);
E_GetRGB8CM(window->WScreen->EScreen, screencolors, 0, MAXCOL);
/* check if the EGS default screen is really an 8 bit screen - if not, exit */
depth = window->WScreen->EScreen->Map->Depth;
#if 0
/* This is the 'old' test - doesn't work on a Spectrum, however, so I removed it for now.. */
if ((window->WScreen->EScreen->Map->Depth != 8) ||
(window->WScreen->EScreen->Map->Type != E_PIXELMAP))
#endif
if (window->WScreen->EScreen->Map->Depth != 8)
Crash("Screen has a wrong depth - we need an 8 bit chunky pixel screen.");
/* for faster access to this structure...*/
rp = window->RPort;
/* now allocate memory for the image via EGS */
map = E_AllocBitMap(wwidth, wheight, 8, E_PIXELMAP, 0, 0);
if (map == NULL)
Crash("could not allocate memory for off-screen bitmap");
/* increase lock counter on map so it doesn't get mapped away */
map->Lock++;
/* old version... data = map->Typekey.PixelMap.Planes.Dest; */
data = map->Plane;
notfirst = 0;
/* Either interpret the file while displaying it */
if (flag_noint)
{
EI_SetWindowTitles(window, fliname, (char *)-1);
if (repeatcount)
{
while (repeatcount--)
{
interpret_fli(fd, &header, data, notfirst, func_disp);
notfirst = 1;
}
}
else
{
for(;;)
{
interpret_fli(fd, &header, data, notfirst, func_disp);
notfirst = 1;
}
}
}
/* Or interpret everything first and display it afterwards */
else
{
text_center("Please wait while loading the animation");
/* Interpret it and store the results */
disp_cur = &disp_root;
interpret_fli(fd, &header, data, 0, func_interp);
/* Now display the results */
EI_SetWindowTitles(window, fliname, (char *)-1);
if (repeatcount)
{
while (repeatcount--)
{
disp_cur = &disp_root;
while (disp_cur->disp_next)
{
disp_cur = disp_cur->disp_next;
/* Only display the first frame once */
if (disp_cur->disp_frame || !notfirst)
display_interp(disp_cur);
}
notfirst = 1;
}
}
else
{
for (;;)
{
disp_cur = &disp_root;
while (disp_cur->disp_next)
{
disp_cur = disp_cur->disp_next;
/* Only display the first frame once */
if (disp_cur->disp_frame || !notfirst)
display_interp(disp_cur);
}
notfirst = 1;
}
}
}
Crash(NULL);
}
void Crash (char *string)
{
/* free bitmaps in display list */
disp_cur = &disp_root;
while (disp_cur->disp_next)
{
disp_cur = disp_cur->disp_next;
if (disp_cur->disp_pix)
{
disp_cur->disp_pix->Lock--;
E_DisposeBitMap(disp_cur->disp_pix);
}
}
if (window)
{
/* restore original color map (only if window was opened before) */
E_SetRGB8CM(window->WScreen->EScreen, oldscreencolors, 0, MAXCOL);
}
if (map)
{
map->Lock--;
E_DisposeBitMap(map);
}
if (window)
EI_CloseWindow(window);
if (screen)
EI_CloseScreen(screen);
if (EGSBase)
CloseLibrary(EGSBase);
if (EGSBlitBase)
CloseLibrary(EGSBlitBase);
if (EGSIntuiBase)
CloseLibrary(EGSIntuiBase);
if (EGSGfxBase)
CloseLibrary(EGSGfxBase);
if (NULL == string)
exit (0);
else
{
printf ("%s.\n", string);
exit (10);
}
}